package cn.t.facade.order;


import cn.t.constants.CommonConstants;
import cn.t.constants.ResponseError;
import cn.t.converter.order.ReplenishmentDTOConverter;
import cn.t.converter.order.ReplenishmentDetailDTOConverter;
import cn.t.converter.order.ReplenishmentRecordDTOConverter;
import cn.t.core.exception.BizException;
import cn.t.core.facade.FacadeImpl;
import cn.t.core.mode.PageInfoDTO;
import cn.t.core.mode.PageQueryDTO;
import cn.t.dto.device.CargowaySkuDTO;
import cn.t.dto.device.vo.OpenCloseDTO;
import cn.t.dto.device.vo.QtyVO;
import cn.t.dto.order.CreateReplenishmentRequest;
import cn.t.dto.order.ReplenishmentDTO;
import cn.t.dto.order.ReplenishmentDetailDTO;
import cn.t.dto.order.ReplenishmentExceptionDTO;
import cn.t.dto.order.ReplenishmentExceptionRequest;
import cn.t.dto.order.base.VBaseDTO;
import cn.t.dto.order.repenlement.ReplenishmentInfoDTO;
import cn.t.dto.order.repenlement.ReplenishmentPageDTO;
import cn.t.dto.order.repenlement.ReplenishmentQueryRequest;
import cn.t.enums.order.ErrorTypeEnum;
import cn.t.enums.order.ReplenishmentStatusEnum;
import cn.t.model.device.DeviceDO;
import cn.t.model.order.ExceptionLogDO;
import cn.t.model.order.ReplenishmentDO;
import cn.t.model.order.ReplenishmentDetailDO;
import cn.t.model.order.ReplenishmentRecordDO;
import cn.t.service.device.DeviceService;
import cn.t.service.order.ExceptionLogService;
import cn.t.service.order.ReplenishmentDetailService;
import cn.t.service.order.ReplenishmentRecordService;
import cn.t.service.order.ReplenishmentService;
import cn.t.service.user.CustomerFirmService;
import cn.t.utils.DateUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 补货订单表(Replenishment)服务编排
 *
 * @author t
 * @since 2024-05-24 10:19:35
 */
@Slf4j
@Service
@AllArgsConstructor
public class ReplenishmentFacade extends FacadeImpl<ReplenishmentDTO, ReplenishmentDO, ReplenishmentDTOConverter, ReplenishmentService> {
    @Resource
    private ReplenishmentDetailService replenishmentDetailService;
    @Resource
    private ReplenishmentRecordService replenishmentRecordService;
    @Resource
    protected Executor executeIoExecutor;
    @Resource
    private CustomerFirmService customerFirmService;
    @Resource
    private DeviceService deviceService;
    @Resource
    private ExceptionLogService exceptionLogService;
    @Resource
    private ReplenishmentRecordDTOConverter replenishmentRecordDTOConverter;
    @Resource
    private ReplenishmentDetailDTOConverter replenishmentDetailDTOConverter;

    public ReplenishmentInfoDTO replenishmentDetailSku(List<String> rsSn) {
        if (CollectionUtils.isEmpty(rsSn)) {
            throw new RuntimeException("补货单号不能为空");
        }
        return service.replenishmentDetailGroupSku(rsSn);
    }

    public PageInfoDTO<ReplenishmentPageDTO> queryList(PageQueryDTO<ReplenishmentQueryRequest> request) {
        List<ReplenishmentDO> replenishmentPageList = service.queryList(request.getParam(), request.getStart(), request.getPageSize());
        //获取补货明细
        List<ReplenishmentPageDTO> list = getReplenishmentPageList(replenishmentPageList);
        return new PageInfoDTO<>(request.getPageNo(), request.getPageSize(), getTotal(request.getParam()), list);
    }

    public Long getTotal(ReplenishmentQueryRequest request) {
        return service.queryListCount(request);
    }

    public ReplenishmentPageDTO findReplenishmentInfo(String rsSn) {
        List<ReplenishmentDO> repositoryList = service.findByModel(new ReplenishmentDO(rsSn.trim()), CommonConstants.ZERO, Integer.MAX_VALUE, null, null);
        if (CollectionUtils.isEmpty(repositoryList)) {
            throw new BizException(ResponseError.RS_DATA_NOTFOUND_ERR, ResponseError.RS_DATA_NOTFOUND_ERR.getName());
        }
        List<ReplenishmentPageDTO> list = getReplenishmentPageList(repositoryList);
        return list.stream().findFirst().get();
    }

    private List<ReplenishmentPageDTO> getReplenishmentPageList(List<ReplenishmentDO> replenishmentPageList) {
        List<String> rsNos = replenishmentPageList.stream().map(ReplenishmentDO::getRsSn).distinct().collect(Collectors.toList());
        List<Long> firmIds = replenishmentPageList.stream().map(ReplenishmentDO::getFirmId).distinct().collect(Collectors.toList());
        List<Long> deviceIds = replenishmentPageList.stream().map(ReplenishmentDO::getDeviceId).distinct().collect(Collectors.toList());
        //所属公司
        Map<Long, String> firmIdNameMap = new HashMap<>();
        if (firmIds.size() > 0) {
            firmIdNameMap = customerFirmService.getFirmIdNameMap(firmIds);
        }
        //设备信息
        Map<Long, DeviceDO> deviceMap = new HashMap<>();
        if (firmIds.size() > 0) {
            deviceMap = deviceService.getDeviceList(null, null, deviceIds).stream().collect(Collectors.toMap(DeviceDO::getId, Function.identity()));
        }

        Map<Long, String> finalFirmIdNameMap = firmIdNameMap;
        List<ReplenishmentDetailDO> byModel = replenishmentDetailService.getReplenishmentDetailList(rsNos);
        Map<String, Integer> detailCountMap = byModel.stream().collect(Collectors.groupingBy(ReplenishmentDetailDO::getRsSn, Collectors.summingInt(ReplenishmentDetailDO::getActualRsQty)));
        Map<String, Integer> sumCountMap = byModel.stream().collect(Collectors.groupingBy(ReplenishmentDetailDO::getRsSn, Collectors.summingInt(ReplenishmentDetailDO::getRsQty)));


        //to vo
        Map<Long, DeviceDO> finalDeviceMap = deviceMap;
        return replenishmentPageList.stream().map(replenishmentPageDTO -> {
            ReplenishmentPageDTO pageDTO = converter.toPageDTO(replenishmentPageDTO);
            DeviceDO deviceDO = finalDeviceMap.get(replenishmentPageDTO.getDeviceId());
            if (deviceDO != null) {
                pageDTO.setDeviceName(deviceDO.getDeviceName());
                pageDTO.setDeviceAddr(deviceDO.getDeviceAddr());
                pageDTO.setDeviceType(deviceDO.getDeviceType());
            }

            Integer count = detailCountMap.get(replenishmentPageDTO.getRsSn());
            pageDTO.setFirmName(finalFirmIdNameMap.get(replenishmentPageDTO.getFirmId()));
            pageDTO.setGmtCreateDateStr(DateUtil.setTime(replenishmentPageDTO.getGmtCreated()));
            pageDTO.setCloseTime(DateUtil.setTime(replenishmentPageDTO.getGmtLastRs()));

            pageDTO.setQty((long) (count));
            pageDTO.setSumNum((long) (sumCountMap.get(replenishmentPageDTO.getRsSn())));
            pageDTO.setRsStatusStr(ReplenishmentStatusEnum.getName(replenishmentPageDTO.getRsStatus()));
            return pageDTO;
        }).collect(Collectors.toList());
    }

    @Transactional
    public String createReplenishment(CreateReplenishmentRequest request) {
        //查询设备信息
        DeviceDO deviceDO = deviceService.findById(request.getDeviceId());
        if (ObjectUtils.isEmpty(deviceDO)){
            throw new BizException(ResponseError.DEVICE_NOT_FOUND, String.format(ResponseError.DEVICE_NOT_FOUND.getName(), request.getDeviceId().toString()));
        }
        String rsSn = service.addReplenishment(deviceDO);
        replenishmentDetailService.addDetail(request.getData(), deviceDO.getId(), rsSn);
        return rsSn;
    }

    public void closeReplenishment(String rsSn) {
        ReplenishmentPageDTO replenishmentInfo = findReplenishmentInfo(rsSn);
        ReplenishmentDO replenishmentDO = new ReplenishmentDO();
        replenishmentDO.setRsSn(rsSn);
        replenishmentDO.setRsStatus(ReplenishmentStatusEnum.CLOSED.getCode());
        service.updateReplenishmentByVO(replenishmentDO);
    }

    public void updateStatus(VBaseDTO<ReplenishmentPageDTO, ReplenishmentDetailDTO> replenishmentVO, OpenCloseDTO openCloseDO) {

        List<ReplenishmentRecordDO> recordList = new ArrayList<>();
        List<ReplenishmentDetailDO> detailList = new ArrayList<>();
        Map<Object, QtyVO> qtyMap = openCloseDO.getQtyList().stream().collect(Collectors.toMap(QtyVO::getNo, Function.identity()));
        for (ReplenishmentDetailDTO replenishmentDetailDTO : replenishmentVO.getDetail()) {

            QtyVO qtyVo = qtyMap.get(replenishmentDetailDTO.getCargowayNo());

            if (qtyVo != null && qtyVo.getErrorTypeEnum() == null) {
                Double qty = Double.valueOf(qtyVo.getQty());
                //补货记录
                if (qty > 0) {
                    //修改单行补货货状态
                    replenishmentDetailDTO.setActualRsQty(qty.intValue() + (replenishmentDetailDTO.getActualRsQty() == null ? 0 : replenishmentDetailDTO.getActualRsQty()));
                    replenishmentDetailDTO.setRsGoodsStatus(ReplenishmentStatusEnum.getStatusEnum
                            (replenishmentDetailDTO.getActualRsQty(), replenishmentDetailDTO.getRsQty()).getCode());


                    detailList.add(replenishmentDetailDTOConverter.dto2Model(replenishmentDetailDTO));

                }
            } else {
                log.warn("货道号异常 {} {}", replenishmentDetailDTO.getRsSn(), replenishmentDetailDTO.getCargowayNo());
            }
        }
        ReplenishmentDO replenishmentDO = new ReplenishmentDO();
        //修改补货单详情
        if (!ObjectUtils.isEmpty(detailList)) {
            replenishmentDO.setGmtLastRs(DateUtil.dateByStr(openCloseDO.getRecordAt()));
            detailList.forEach(replenishmentDetailDO -> {
                replenishmentDetailDO.setModifier(openCloseDO.getOperatorInfo());
            });
            replenishmentDetailService.updateBatchDetail(detailList);
        }
        Integer statusEnum;
        boolean isDettled = replenishmentVO.getDetail().stream().allMatch(replenishmentDetailDTO -> ReplenishmentStatusEnum.closedList.contains(replenishmentDetailDTO.getRsGoodsStatus()));
        if (isDettled) {
            statusEnum = ReplenishmentStatusEnum.SETTLED.getCode();
        } else {
            boolean partiallyCompleted = replenishmentVO.getDetail().stream().allMatch(replenishmentDetailDTO -> ReplenishmentStatusEnum.PENDING.getCode().equals(replenishmentDetailDTO.getRsGoodsStatus()));
            if (partiallyCompleted) {
                statusEnum = ReplenishmentStatusEnum.PENDING.getCode();
            } else {
                statusEnum = ReplenishmentStatusEnum.PARTIALLY_COMPLETED.getCode();
            }
        }

        replenishmentDO.setId(replenishmentVO.getDataMain().getId());
        replenishmentDO.setRsStatus(statusEnum);
        replenishmentDO.setParticipantId(openCloseDO.getParticipantId());
        replenishmentDO.setUserId(openCloseDO.getUserId());
        replenishmentDO.setUserName(openCloseDO.getUserName());
        replenishmentDO.setModifier(openCloseDO.getOperatorInfo());
        service.update(replenishmentDO);

        //补货记录
        for (QtyVO qtyVO : openCloseDO.getQtyList()) {
            CargowaySkuDTO cargowaySkuDO = openCloseDO.getCargowaySkuMap().get(qtyVO.getNo());
            Integer qty = qtyVO.getQty();
            //补货记录
            if (qtyVO.getWeight() != null && qtyVO.getQty() != null && qty > 0) {
                if (qtyVO.getWeight() < 0) {
                    qty = qty * -1;
                }
                //新增补货记录
                ReplenishmentRecordDO replenishmentRecordDO = this.replenishmentRecordDTOConverter.dto2ReplenishmentRecord(cargowaySkuDO, qty);
                replenishmentRecordDO.setRequestId(openCloseDO.getRequestId());
                replenishmentRecordDO.setUserId(openCloseDO.getUserId());
                replenishmentRecordDO.setFirmId(openCloseDO.getFirmId());
                replenishmentRecordDO.setModifier(openCloseDO.getOperatorInfo());
                replenishmentRecordDO.setCreator(openCloseDO.getOperatorInfo());
                recordList.add(replenishmentRecordDO);
            }
        }
        CompletableFuture.runAsync(() -> {
            //新增库存记录
            if (!ObjectUtils.isEmpty(recordList)) {
                replenishmentRecordService.addBatch(recordList);
            }
        }, executeIoExecutor);
    }

    public PageInfoDTO<ReplenishmentExceptionDTO> getErrRsList(PageQueryDTO<ReplenishmentExceptionRequest> pageList) {
        ExceptionLogDO exceptionLogDO = converter.requestToExceptionLogDO(pageList.getParam());
        List<ExceptionLogDO> exceptionLogList = exceptionLogService.findByModel(exceptionLogDO, pageList.getStart(), pageList.getPageSize(), " id ", " desc");
        if (CollectionUtils.isEmpty(exceptionLogList)) {
            return new PageInfoDTO<>(pageList.getPageNo(), pageList.getPageSize(), 0, new ArrayList<>());

        }
        List<Long> deviceList = exceptionLogList.stream().map(ExceptionLogDO::getDeviceId).filter(Objects::nonNull).distinct().collect(Collectors.toList());

        //deviceList
        Map<Long, DeviceDO> deviceBeanMap = new HashMap<>();
        if (deviceList.size() > 0) {
            deviceBeanMap = deviceService.
                    getDeviceList(null, null, deviceList).stream().collect(Collectors.toMap(DeviceDO::getId, Function.identity()));
        }
        Map<Long, DeviceDO> finalDeviceBeanMap = deviceBeanMap;
        List<ReplenishmentExceptionDTO> collect = exceptionLogList.stream().map(exceptionLogDo -> {
            ReplenishmentExceptionDTO replenishmentExceptionDTO = new ReplenishmentExceptionDTO();
            replenishmentExceptionDTO.setRsSn(exceptionLogDo.getOrderSn());
            DeviceDO deviceDO = finalDeviceBeanMap.get(exceptionLogDo.getDeviceId());
            if (deviceDO != null) {
                replenishmentExceptionDTO.setDeviceName(deviceDO.getDeviceName());
            }
            replenishmentExceptionDTO.setDeviceId(exceptionLogDo.getDeviceId());
            replenishmentExceptionDTO.setCargowayNo(exceptionLogDo.getCargowayNo());
            replenishmentExceptionDTO.setSkuName(exceptionLogDo.getSkuName());
            replenishmentExceptionDTO.setSkuCode(exceptionLogDo.getSkuCode());
            replenishmentExceptionDTO.setExceptionType(exceptionLogDo.getExceptionType());
            replenishmentExceptionDTO.setExceptionTypeStr(ErrorTypeEnum.getDescByKey(exceptionLogDo.getExceptionType()));
            replenishmentExceptionDTO.setGmtCreateDate(DateUtil.setTime(exceptionLogDo.getGmtCreated()));
            replenishmentExceptionDTO.setUserName(exceptionLogDo.getUserName());
            return replenishmentExceptionDTO;
        }).collect(Collectors.toList());
        return new PageInfoDTO<>(pageList.getPageNo(), pageList.getPageSize(), exceptionLogList.size(), collect);
    }
}

